﻿using System.Collections.ObjectModel;
using System.ComponentModel;

namespace EasyXaf.LowCode.WorkflowEditors.Models;

public class ObjectCollection<T> : ObservableCollection<T>, INotifyPropertyChanging
    where T : IFlowObject
{
    public IFlowObject Owner { get; }

    public event PropertyChangingEventHandler PropertyChanging;

    public ObjectCollection(IFlowObject owner)
    {
        Owner = owner;
    }

    protected void OnPropertyChanging(string propertyName)
    {
        if (!Owner.IsUpdateLocked)
        {
            PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
        }
    }

    protected override void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (!Owner.IsUpdateLocked)
        {
            base.OnPropertyChanged(e);
        }
    }

    protected void OnIndexerPropertyChanging()
    {
        OnPropertyChanging("Item[]");
    }

    protected void OnItemPropertyChanging()
    {
        OnPropertyChanging("Item");
    }

    protected void OnItemPropertyChanged()
    {
        OnPropertyChanged(new PropertyChangedEventArgs("Item"));
    }

    private void Item_PropertyChanging(object sender, PropertyChangingEventArgs e)
    {
        OnItemPropertyChanging();
    }

    private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        OnItemPropertyChanged();
    }

    private void SubscribeToItemEvents(T item)
    {
        item.PropertyChanging += Item_PropertyChanging;
        item.PropertyChanged += Item_PropertyChanged;
    }

    private void UnsubscribeFromItemEvents(T item)
    {
        item.PropertyChanging -= Item_PropertyChanging;
        item.PropertyChanged -= Item_PropertyChanged;
    }

    protected override void ClearItems()
    {
        foreach (var item in Items)
        {
            UnsubscribeFromItemEvents(item);
        }

        OnIndexerPropertyChanging();
        base.ClearItems();
    }

    protected override void RemoveItem(int index)
    {
        var item = Items.ElementAt(index);
        if (item != null)
        {
            UnsubscribeFromItemEvents(item);
        }

        OnIndexerPropertyChanging();
        base.RemoveItem(index);
    }

    protected override void InsertItem(int index, T item)
    {
        if (!Items.Any(x => x.Id == item.Id))
        {
            UnsubscribeFromItemEvents(item);
            SubscribeToItemEvents(item);
            OnIndexerPropertyChanging();
            base.InsertItem(index, item);
        }
    }

    protected override void SetItem(int index, T item)
    {
        OnIndexerPropertyChanging();
        base.SetItem(index, item);
    }

    protected override void MoveItem(int oldIndex, int newIndex)
    {
        OnIndexerPropertyChanging();
        base.MoveItem(oldIndex, newIndex);
    }
}
